#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <string>
#include <codecvt>
#include <algorithm>

class utils
{
public:
	static std::wstring utf8_to_wide(const std::string& utf8)
	{
		std::wstring_convert<std::codecvt_utf8<wchar_t>> utfconv;
		return utfconv.from_bytes(utf8);
	}

	static std::string wide_to_ansi(const std::wstring& wstr)
	{
		int nAnsi = ::WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), NULL, 0, NULL, NULL);
		std::unique_ptr<char[]> buffer(new char[nAnsi + 1]);
		if (!buffer)
			return "";
		::WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), buffer.get(), nAnsi, NULL, NULL);
		buffer[nAnsi] = '\0';
		return buffer.get();
	}

	static std::string utf8_to_ansi(const std::string& utf8)
	{
		return wide_to_ansi(utf8_to_wide(utf8));
	}

	static std::string string_remove_chars(std::string& value, const char* chars)
	{
		std::string result = value;
		for (unsigned int i = 0; i < strlen(chars); ++i)
		{
			result.erase(std::remove(result.begin(), result.end(), chars[i]), result.end());
		}

		return result;
	}

	template<typename ... Args>
	static std::string string_format(const std::string& format, Args ... args)
	{
		int size_s = std::snprintf(nullptr, 0, format.c_str(), args ...) + 1;
		if (size_s <= 0) { throw std::runtime_error("Error during formatting."); }
		auto size = static_cast<size_t>(size_s);
		auto buf = std::make_unique<char[]>(size);
		std::snprintf(buf.get(), size, format.c_str(), args ...);
		return std::string(buf.get(), buf.get() + size - 1);
	}

	static std::string replace_all(std::string str, const std::string old, const std::string new_s) 
	{
		if (!old.empty()) {
			size_t pos = str.find(old);
			while ((pos = str.find(old, pos)) != std::string::npos) {
				str = str.replace(pos, old.length(), new_s);
				pos += new_s.length();
			}
		}
		return str;
	}

	template<typename T,typename BT,typename OT>
	static T get_ptr(BT base, OT offset)
	{
		return reinterpret_cast<T>((uintptr_t)base + (uintptr_t)offset);
	}

	template<typename T, typename BT, typename OT>
	static T read_ptr(BT base, OT offset)
	{
		T adr = get_ptr<T>(base, offset);
		if (!IsBadReadPtr((void*)adr, sizeof(T)))
			return *(T*)adr;

		return T();
	}

	template<typename ... Args>
	static void debug_log(const char* fmt, Args... args)
	{
		std::string log = std::string("SotckTiny:[") + fmt +"]";
		log = string_format(log, args...);
		OutputDebugStringA(log.data());
	}
};

#ifdef _DEBUG
#define LOG(fmt,...) utils::debug_log(fmt,__VA_ARGS__)
#else
#define LOG(fmt,...)
#endif // _DEBUG